/*
 *   Copyright 2011-2012 Hai Bison
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/*
 * FrameMain.java
 *
 * Created on Sep 10, 2011, 2:51:39 PM
 */
package group.pals.mailgate;

import group.pals.mailgate.commons.Lib;
import group.pals.mailgate.ui.MouseAdapter;
import group.pals.mailgate.ui.MouseHandler;
import group.pals.mailgate.utils.Initialization;
import group.pals.mailgate.preferences.Preferences;
import group.pals.mailgate.preferences.PreferencesAdapter;
import group.pals.mailgate.utils.Utils;
import group.pals.threads.BaseThread;
import group.pals.threads.ThreadManager;
import group.pals.utils.sys.ArgsUtils;
import group.pals.utils.sys.MessageBox;
import group.pals.utils.sys.SysUtils;
import java.awt.AWTException;
import java.awt.Frame;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

/**
 *
 * @author Hai Bison
 */
public class FrameMain extends javax.swing.JFrame {

    private final Preferences _Preferences;
    private final PanelProject _PanelProject;
    private final Utils _Utils;
    private final ThreadManager _ThreadManager;
    private final PopupMenu PopupMenuTray;
    private final MouseHandler TrayIconMouseHandler;

    /** Creates new form FrameMain */
    public FrameMain() {
        initComponents();

        this._Preferences = Preferences.getInstance();
        this._PanelProject = new PanelProject(this);
        this._Utils = Utils.getInstance();
        this._ThreadManager = ThreadManager.getInstance();
        this.PopupMenuTray = new PopupMenu(_Utils.getAppTitleWithVersion());
        this.TrayIconMouseHandler = new MouseHandler(_Preferences.getMouseDblClickSensitivity());

        initialize();
        initActions();
        initListeners();
        initUI();

        initUpdater();
    }
    /*----------------------------------------------------------------------------
     * UTILITIES
     */
    private final JFrame TheFrameMain = this;

    private void initialize() {
        _Utils.initialize();
    }

    private void initUI() {
        /*
         * In Vietnam, 51 is a dog, who is my best friend  :-)
         */
        group.pals.utils.ui.Utils.setWindowCenterScreen(this, 51);

        //title
        setTitle(_Utils.getAppTitleWithVersion());
        //logo
        setIconImages(_Utils.getMainIcons());
        //panel project
        setContentPane(_PanelProject);

        addWindowListener(new WindowAdapter() {

            @Override
            public void windowOpened(WindowEvent e) {
                //check if this is first run
                if (_Preferences.getAuthUsername() == null) {
                    actionShowDialogPreferences.actionPerformed(new ActionEvent(e.getWindow(), ActionEvent.ACTION_PERFORMED, ""));
                } else if (_Preferences.isMinimizeOnStart()) {
                    setVisible(false);
                }
            }

            @Override
            public void windowClosing(WindowEvent e) {
                //TODO: this method runs infinitively
                if (true) {
                    return;
                }

                List<BaseThread> threads = _ThreadManager.cloneAllThreads();
                for (BaseThread thread : threads) {
                    thread.interrupt();
                }
                while (!_ThreadManager.isEmpty()) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException ie) {
                        break;
                    }
                }
            }

            @Override
            public void windowIconified(WindowEvent e) {
                setVisible(false);
            }
        });//window listener

        //tray-icon
        initPopupMenuTray();
        try {
            initTrayIcon();
        } catch (AWTException awte) {
        }
    }

    private void initUpdater() {
        if (_Preferences.isAutoUpdateOn()) {
            _Utils.startUpdater();
        }
    }

    private void initPopupMenuTray() {
        MenuItem miShowDialogPreferences = new MenuItem((String) actionShowDialogPreferences.getValue(AbstractAction.NAME));
        miShowDialogPreferences.addActionListener(actionShowDialogPreferences);
        PopupMenuTray.add(miShowDialogPreferences);

        MenuItem miShowAboutBox = new MenuItem((String) actionShowAbout.getValue(AbstractAction.NAME));
        miShowAboutBox.addActionListener(actionShowAbout);
        PopupMenuTray.add(miShowAboutBox);

        PopupMenuTray.addSeparator();

        MenuItem miExit = new MenuItem((String) actionExit.getValue(AbstractAction.NAME));
        miExit.addActionListener(actionExit);
        PopupMenuTray.add(miExit);
    }

    private void initTrayIcon() throws AWTException {
        if (!SystemTray.isSupported()) {
            return;
        }

        //assumed tray-icon is square
        final int TrayIconDim = SystemTray.getSystemTray().getTrayIconSize().height;
        //note: largest first
        final int[] TrayIconSizes = {128, 96, 80, 64, 48, 32, 24, 16};
        int trayIconSize = TrayIconSizes[0];
        for (int size : TrayIconSizes) {
            if (Math.abs(size - TrayIconDim) < Math.abs(trayIconSize - TrayIconDim)) {
                trayIconSize = size;
            }
        }
        ImageIcon img = _Utils.getIcon(trayIconSize);
        final TrayIcon TheTrayIcon = SysUtils.initTrayIcon(img != null ? img.getImage() : null,
                _Utils.getAppTitleWithVersion(), PopupMenuTray);
        if (TheTrayIcon == null) {
            return;
        }
        TheTrayIcon.setImageAutoSize(true);
        TrayIconMouseHandler.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseSingleClicked(MouseEvent e) {
                _PanelProject.togglePopupMessagesVisileStatus();
            }

            @Override
            public void mouseDoubleClicked(MouseEvent e) {
                setVisible(!isVisible());
                if (isVisible()) {
                    setState(Frame.NORMAL);
                    toFront();
                    requestFocus();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    //PopupMenuTray.show(TheFrameMain, e.getX(), e.getY());
                }
            }
        });
        TheTrayIcon.addMouseListener(TrayIconMouseHandler);
    }

    private void initListeners() {
        _Preferences.addPreferencesListener(new PreferencesAdapter() {

            @Override
            public void preferencesStored() {
                TrayIconMouseHandler.setDoubleClickDelayTime(_Preferences.getMouseDblClickSensitivity());
                _Utils.restartUpdater();
            }
        });
    }

    private void initActions() {
        actionMinimize = new ActionMinimize();
        actionShowDialogPreferences = new ActionShowDialogPreferences();
        actionShowAbout = new ActionShowAbout();
        actionExit = new ActionExit();

        menuItemMinimize.setAction(actionMinimize);
        menuItemPreferences.setAction(actionShowDialogPreferences);
        menuItemAbout.setAction(actionShowAbout);
        menuItemExit.setAction(actionExit);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        menuBarMain = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        menuItemMinimize = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        menuItemExit = new javax.swing.JMenuItem();
        jMenu2 = new javax.swing.JMenu();
        menuItemPreferences = new javax.swing.JMenuItem();
        jMenu3 = new javax.swing.JMenu();
        menuItemAbout = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jMenu1.setText("Control");

        menuItemMinimize.setText("jMenuItem1");
        jMenu1.add(menuItemMinimize);
        jMenu1.add(jSeparator1);

        menuItemExit.setText("jMenuItem2");
        jMenu1.add(menuItemExit);

        menuBarMain.add(jMenu1);

        jMenu2.setText("Tools");

        menuItemPreferences.setText("jMenuItem3");
        jMenu2.add(menuItemPreferences);

        menuBarMain.add(jMenu2);

        jMenu3.setText("Help");

        menuItemAbout.setText("jMenuItem4");
        jMenu3.add(menuItemAbout);

        menuBarMain.add(jMenu3);

        setJMenuBar(menuBarMain);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 279, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        //check if the user execute the application by launcher or itself
        ArgsUtils au = new ArgsUtils(args);
        try {
            final Long nanotime = Long.parseLong(au.getValueAsString(Lib.ArgNanoTime), Character.MAX_RADIX);
            if (System.nanoTime() - nanotime > 8e9) //8 seconds, my lucky number  :-)
            {
                throw new Exception();
            }
        } catch (Exception ex) {
            MessageBox.showInfoMsg(null, null, "Please execute the application by Launcher (launcher.jar)\n"
                    + "to get full features supported");
        }

        //check version
        final String JvmVersion = System.getProperty("java.version");
        if (JvmVersion.compareTo("1.6") < 0) {
            MessageBox.showInfoMsg(null, null,
                    String.format("Your Java version: %s.\n"
                    + "Plesae use Java from 1.6 and up for better performance.",
                    JvmVersion));
        }

        /* Set the default Java look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        try {
            //DO NOT USE DEFAULT LOOK AND FEEL
            //ON WINDOWS, THIS WILL RAISE SOME FAILS OF UI
//      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (Exception ex) {
            java.util.logging.Logger.getLogger(FrameMain.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        final Preferences ThePreferences = Preferences.getInstance();
        final Utils TheUtils = Utils.getInstance();

        if (ThePreferences.isUseMasterPassword()) {
            DialogSignIn dp = new DialogSignIn(null, true);
            dp.setVisible(true);
        } else {
            if (ThePreferences.getAuthUsername() == null) {
                //first run, do nothing
            } else {
                String tmp = Utils.JvmUniqueID + TheUtils.getUsername();
                if (!ThePreferences.userLogin(tmp)) {
                    MessageBox.showErrMsg(null, null, "Active user is not owner!");
                    System.exit(0);
                }
            }
        }

        //initialize environment
        Initialization.getInstance();

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new FrameMain().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JMenuBar menuBarMain;
    private javax.swing.JMenuItem menuItemAbout;
    private javax.swing.JMenuItem menuItemExit;
    private javax.swing.JMenuItem menuItemMinimize;
    private javax.swing.JMenuItem menuItemPreferences;
    // End of variables declaration//GEN-END:variables

    /*----------------------------------------------------------------------------
     * ACTIONS
     */

    /*----------------------------------------------------------------------------
     * ActionMinimize
     */
    private ActionMinimize actionMinimize;

    private class ActionMinimize extends AbstractAction {

        public ActionMinimize() {
            super("Minimize to system tray");
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0));
        }

        public void actionPerformed(ActionEvent e) {
            if (!SystemTray.isSupported()) {
                MessageBox.showInfoMsg(null, null, "Your system does not support system tray");
            }
            setVisible(false);
        }
    }

    /*----------------------------------------------------------------------------
     * ActionShowDialogPreferences
     */
    private ActionShowDialogPreferences actionShowDialogPreferences;

    private class ActionShowDialogPreferences extends AbstractAction {

        private DialogPreferences dialogPreferences = null;

        public ActionShowDialogPreferences() {
            super("Preferences...");
            putValue(ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke('P', InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
        }

        public void actionPerformed(ActionEvent e) {
            if (dialogPreferences == null) {
                dialogPreferences = new DialogPreferences(TheFrameMain, true);
                dialogPreferences.addWindowListener(new WindowAdapter() {

                    @Override
                    public synchronized void windowOpened(WindowEvent e) {
                        setEnabled(false);
                    }

                    @Override
                    public synchronized void windowClosed(WindowEvent e) {
                        TheFrameMain.setEnabled(true);
                        setEnabled(true);
                        dialogPreferences = null;
                    }
                });
                dialogPreferences.setVisible(true);
            } else {
                dialogPreferences.toFront();
                dialogPreferences.requestFocus();
            }
        }
    }

    /*----------------------------------------------------------------------------
     * ActionMinimize
     */
    private ActionShowAbout actionShowAbout;

    private class ActionShowAbout extends AbstractAction {

        private DialogAbout dialogAbout = null;

        public ActionShowAbout() {
            super("About...");
        }

        public void actionPerformed(ActionEvent e) {
            if (dialogAbout == null) {
                dialogAbout = new DialogAbout(TheFrameMain, true);
                dialogAbout.addWindowListener(new WindowAdapter() {

                    @Override
                    public synchronized void windowOpened(WindowEvent e) {
                        setEnabled(false);
                    }

                    @Override
                    public synchronized void windowClosed(WindowEvent e) {
                        TheFrameMain.setEnabled(true);
                        setEnabled(true);
                        dialogAbout = null;
                    }
                });
                dialogAbout.setVisible(true);
            } else {
                dialogAbout.toFront();
                dialogAbout.requestFocus();
            }
        }
    }

    /*----------------------------------------------------------------------------
     * ActionExit
     */
    private ActionExit actionExit;

    private class ActionExit extends AbstractAction {

        public ActionExit() {
            super("Exit");
        }

        public void actionPerformed(ActionEvent e) {
            TheFrameMain.dispatchEvent(new WindowEvent(TheFrameMain, WindowEvent.WINDOW_CLOSING));
        }
    }
}
